import HashEventListener, { HashEventHandler } from 'listener'
import {
    RES_COLOR_MAP,
    b_blueRes,
    b_greenRes,
    b_greyRes,
    b_pinkRes,
    b_witheRes,
    b_yellowRes,
    barsRes,
    baseRes,
    c_blueRes,
    c_greenRes,
    c_greyRes,
    c_pinkRes,
    c_yellowRes,
    powerRes,
} from './constants'
import { screepsApi } from 'utils/request'
import { IRoomObjects, Shard } from 'utils/screeps'
import { ResourceConstant } from 'utils/resource'
import './index.less'
import { splitThousands } from 'utils/common'
import { usernames } from 'utils/user'

const prefix = 'keqing-queryres'

export type ResStats = {
    [key in ResourceConstant]?: {
        [roomName: string]: number
    }
}

/**
 * 查询玩家资源
 */
export default class QueryRes implements HashEventHandler {
    public readonly moduleName = '查询玩家资源'

    public readonly localStorageKey = 'QueryRes'

    public enable: boolean

    public readonly resMap: {
        [key: string]: string[][]
    } = {
        基础资源: [[...baseRes, ...powerRes]],
        bar资源: [barsRes],
        商品资源: [c_greyRes, c_yellowRes, c_greenRes, c_blueRes, c_pinkRes],
        化合物资源: [b_greyRes, b_blueRes, b_pinkRes, b_greenRes, b_yellowRes, b_witheRes],
    }

    public constructor() {
        this.enable = HashEventListener.getModuleEnable(this.localStorageKey)
    }

    public setEnable(enable: boolean) {
        this.enable = enable
        HashEventListener.setModuleEnable(this.localStorageKey, enable)
    }

    public async triggerPanel() {
        const panel = document.createElement('div')
        const h3 = document.createElement('h3')
        const searchDiv = document.createElement('div')
        const smartInputDiv = document.createElement('div')
        const input = document.createElement('input')
        const tips = document.createElement('ul')
        const sshard = document.createElement('div')
        const searchButton = document.createElement('button')
        const closeButton = document.createElement('button')

        h3.innerHTML = '查询玩家资源'
        input.setAttribute('placeholder', '请输入玩家名：')
        input.setAttribute('type', 'text')
        sshard.innerHTML = `
            <span>请选择shard：</span>
            <ul>
                <li>s0</li>
                <li>s1</li>
                <li>s2</li>
                <li class="active">s3</li>
            </ul>
        `
        searchButton.innerHTML = '搜索'
        closeButton.innerHTML = '关闭'

        panel.setAttribute('class', `${prefix}-panel`)
        searchDiv.setAttribute('class', `${prefix}-search`)
        smartInputDiv.setAttribute('class', `${prefix}-smart-input`)
        tips.setAttribute('class', `${prefix}-tips`)
        sshard.setAttribute('class', `${prefix}-sshard`)

        input.addEventListener('input', (e) => {
            const target = e.target
            if (!(target instanceof HTMLInputElement)) return
            if (target.value) {
                tips.innerHTML = ''
                // 限制提示的数量
                let num = 15
                for (const username of usernames) {
                    if (!num) break
                    if (username.toLocaleLowerCase().startsWith(target.value.toLocaleLowerCase())) {
                        const li = document.createElement('li')
                        li.innerText = username
                        tips.appendChild(li)
                        num--
                    }
                }
            } else {
                tips.innerHTML = ''
            }
        })

        tips.addEventListener('click', (e) => {
            const target = e.target
            if (target instanceof HTMLLIElement) {
                input.value = target.innerText
                tips.innerHTML = ''
            }
        })

        sshard.addEventListener('click', (e) => {
            const target = e.target
            if (target instanceof HTMLLIElement) {
                // 有active类名就移除，没有就添加
                target.classList.toggle('active')
            }
        })

        searchButton.addEventListener('click', async () => {
            const username = input.value
            const shards: Shard[] = []
            const shardMap: { [alias: string]: Shard } = {
                s0: 'shard0',
                s1: 'shard1',
                s2: 'shard2',
                s3: 'shard3',
            }
            sshard.querySelectorAll('li').forEach((li) => {
                if (li.classList.contains('active')) {
                    shards.push(`${shardMap[li.innerHTML.trim()]}` as Shard)
                }
            })
            // 清除旧的表格
            const oldTable = document.querySelector(`.${prefix}-table`)
            if (oldTable) {
                oldTable.remove()
            }

            const resStats = await this.search(username, shards)
            if (!resStats) {
                return alert('查询失败')
            }
            try {
                const table = this.createResTable(resStats)
                panel.appendChild(table)
            } catch (error) {
                console.log('error', error)
            }
        })

        closeButton.addEventListener('click', () => {
            panel.remove()
        })

        this.addWheelEvent(panel)

        smartInputDiv.appendChild(input)
        smartInputDiv.appendChild(tips)
        searchDiv.appendChild(smartInputDiv)
        searchDiv.appendChild(sshard)
        searchDiv.appendChild(searchButton)
        searchDiv.appendChild(closeButton)
        panel.appendChild(h3)
        panel.appendChild(searchDiv)

        document.body.appendChild(panel)
    }

    /**
     * 搜索玩家资源
     */
    public async search(username: string, shards: Shard[]) {
        const userInfo = await screepsApi.getUserInfoByUserName(username)
        if (!userInfo.ok || !userInfo.user) {
            return alert(`获取用户${username}信息失败`)
        }
        const roomsInfo = await screepsApi.getRooms(userInfo.user._id)
        if (!roomsInfo.ok || !roomsInfo.shards) {
            return alert(`获取用户${username}房间信息失败`)
        }

        const resStats: ResStats = {}

        for (const shard of shards) {
            const requests: Promise<IRoomObjects>[] = []

            for (const room of roomsInfo.shards[shard]) {
                requests.push(screepsApi.getRoomObject(room, shard))
            }

            await Promise.all(requests).then((ress) => {
                ress.forEach((res) => {
                    if (!res.ok) return
                    for (const object of res.objects) {
                        if (object.type !== 'storage' && object.type !== 'terminal' && object.type !== 'factory')
                            continue
                        for (const resType in object.store) {
                            const type = resType as ResourceConstant
                            if (!resStats[type]) {
                                resStats[type] = {}
                            }
                            const resStatsType = resStats[type] as { [roomName: string]: number }
                            const roomKey = `${shard}/${object.room}`
                            if (!resStatsType[roomKey]) {
                                resStatsType[roomKey] = 0
                            }
                            resStatsType[roomKey] += object.store[type]
                        }
                    }
                })
            })
        }

        return resStats
    }

    /**
     * 创建资源表格
     */
    public createResTable(resStats: ResStats) {
        const table = document.createElement('div')
        for (const rowName in this.resMap) {
            const row = this.createResRow(rowName, this.resMap[rowName], resStats)
            table.appendChild(row)
        }
        table.setAttribute('class', `${prefix}-table`)
        return table
    }

    /**
     * 创建资源行
     */
    public createResRow(rowName: string, resList: string[][], resStats: ResStats) {
        const row = document.createElement('div')
        const rowTitle = document.createElement('p')
        rowTitle.innerHTML = rowName
        row.appendChild(rowTitle)

        resList.forEach((res) => {
            const rowContent = document.createElement('div')
            rowContent.setAttribute('class', `${prefix}-row-content`)
            res.forEach((resType) => {
                const resEle = document.createElement('div')
                resEle.setAttribute('class', `${prefix}-row-item`)
                const resTitle = document.createElement('span')
                const resAmount = document.createElement('span')
                resTitle.innerHTML = resType
                const amount = Object.values(resStats[resType as ResourceConstant] || {}).reduce((a, b) => a + b, 0)
                resAmount.innerHTML = splitThousands(amount)
                resTitle.setAttribute('style', `color: ${RES_COLOR_MAP[resType]}`)
                resAmount.setAttribute('style', `color: ${RES_COLOR_MAP[resType]}`)
                resEle.appendChild(resTitle)
                resEle.appendChild(resAmount)
                rowContent.appendChild(resEle)
            })
            row.appendChild(rowContent)
        })

        row.setAttribute('class', `${prefix}-row`)
        return row
    }

    /**
     * 添加滚轮事件
     * @param ele 要添加滚轮事件的元素
     */
    public addWheelEvent(ele: HTMLElement) {
        ele.addEventListener('mousewheel', (e) => {
            e.preventDefault()
            if (!(e instanceof WheelEvent)) return
            // 滚动的方向
            const direction = e.deltaY > 0 ? 'down' : 'up'
            // 获取已经缩放的比例
            const scale = ele.style.transform.match(/scale\((\d+(\.\d+)?)\)/)
            let scaleValue = scale ? Number(scale[1]) : 1
            // 缩放panel
            if (direction === 'up') {
                scaleValue = scaleValue <= 0.5 ? 0.5 : scaleValue - 0.01
                ele.style.transform = `translate(-50%, -50%) scale(${scaleValue})`
            } else {
                scaleValue = scaleValue >= 1.2 ? 1.2 : scaleValue + 0.01
                ele.style.transform = `translate(-50%, -50%) scale(${scaleValue})`
            }
        })
    }
}
